﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using Client.p2p;
using System.IO;
using System.Collections.Specialized;

namespace Client
{
    public partial class PrivateChatCtrl : UserControl
    {
        private string LocalName;
        private string TargetName;
        private MessageProcessor msgPro;
        private bool CtrlEnter2Send = true;
        public bool FileTransfering = false;

        #region Constructors

        public PrivateChatCtrl(string LocalName, string TargetName, MessageProcessor msgPro)
        {
            InitializeComponent();
            this.LocalName = LocalName;
            this.TargetName = TargetName;
            this.msgPro = msgPro;
            this.msgPro.FileConfirmed += new FileConfirmedEventHandler(msgPro_FileConfirmed);
            this.msgPro.FileDenied += new FileDeniedEventHandler(msgPro_FileDenied);
            this.msgPro.FileCanceled += new FileCanceledEventHandler(msgPro_FileCanceled);
            this.richTextBoxEdit.AllowDrop = true;
            this.richTextBoxEdit.DragDrop += new DragEventHandler(richTextBoxEdit_DragDrop);
            this.tabControl1.Controls.Remove(this.tabPageFileTransfer);

            //WebBrowser for Target
            string userinfo = Properties.Resources.userinfo;
            userinfo = userinfo.Replace("$$path$$", Application.StartupPath);
            userinfo = userinfo.Replace("$$name$$", this.TargetName);
            userinfo = userinfo.Replace("$$qq$$", this.msgPro.UserData.Users[this.TargetName].UserInfo.QQ);
            userinfo = userinfo.Replace("$$msn$$", this.msgPro.UserData.Users[this.TargetName].UserInfo.MSN);
            userinfo = userinfo.Replace("$$email$$", this.msgPro.UserData.Users[this.TargetName].UserInfo.Email);
            userinfo = userinfo.Replace("$$phone$$", this.msgPro.UserData.Users[this.TargetName].UserInfo.Phone);
            if (this.msgPro.UserData.Users[this.TargetName].AssignProj.Count == 0)
            {
                userinfo = userinfo.Replace("$$project$$", "");
                userinfo = userinfo.Replace("$$job$$", "");
            }
            else
            {
                string strtmp = "";
                for (int i = 0; i < this.msgPro.UserData.Users[this.TargetName].AssignProj.Count;i++)
                {
                    UserData.UserAssignProj assign = this.msgPro.UserData.Users[this.TargetName].AssignProj[i];
                    if (i == 0)
                    {
                        strtmp += "<option value=\"" +
                            assign.Job +
                            "\" selected>" +
                            this.msgPro.UserData.Projects[assign.ProjId].ProjName +
                            "</option>";
                    }
                    else
                    {
                        strtmp += "<option value=\"" +
                            assign.Job +
                            "\">" +
                            this.msgPro.UserData.Projects[assign.ProjId].ProjName +
                            "</option>";
                    }
                }
                userinfo = userinfo.Replace("$$project$$", strtmp);
                userinfo = userinfo.Replace("$$job$$", this.msgPro.UserData.Users[this.TargetName].AssignProj[0].Job);
            }
            this.webBrowserTarget.DocumentText = userinfo;

            //WebBrowser for Local
            userinfo = Properties.Resources.userinfo;
            userinfo = userinfo.Replace("$$path$$", Application.StartupPath);
            userinfo = userinfo.Replace("$$name$$", this.LocalName);
            userinfo = userinfo.Replace("$$qq$$", this.msgPro.UserData.Users[this.LocalName].UserInfo.QQ);
            userinfo = userinfo.Replace("$$msn$$", this.msgPro.UserData.Users[this.LocalName].UserInfo.MSN);
            userinfo = userinfo.Replace("$$email$$", this.msgPro.UserData.Users[this.LocalName].UserInfo.Email);
            userinfo = userinfo.Replace("$$phone$$", this.msgPro.UserData.Users[this.LocalName].UserInfo.Phone);
            if (this.msgPro.UserData.Users[this.LocalName].AssignProj.Count == 0)
            {
                userinfo = userinfo.Replace("$$project$$", "");
                userinfo = userinfo.Replace("$$job$$", "");
            }
            else
            {
                string strtmp = "";
                for (int i = 0; i < this.msgPro.UserData.Users[this.LocalName].AssignProj.Count; i++)
                {
                    UserData.UserAssignProj assign = this.msgPro.UserData.Users[this.LocalName].AssignProj[i];
                    if (i == 0)
                    {
                        strtmp += "<option value=\"" +
                            assign.Job +
                            "\" selected>" +
                            this.msgPro.UserData.Projects[assign.ProjId].ProjName +
                            "</option>";
                    }
                    else
                    {
                        strtmp += "<option value=\"" +
                            assign.Job +
                            "\">" +
                            this.msgPro.UserData.Projects[assign.ProjId].ProjName +
                            "</option>";
                    }
                }
                userinfo = userinfo.Replace("$$project$$", strtmp);
                userinfo = userinfo.Replace("$$job$$", this.msgPro.UserData.Users[this.LocalName].AssignProj[0].Job);
            }
            this.webBrowserLocal.DocumentText = userinfo;
        }

        #endregion

        #region Private Methods

        private void PrivateChatCtrl_Load(object sender, EventArgs e)
        {
//             this.textBoxSenderInfo.Text = this.LocalName;
//             this.textBoxTargetInfo.Text = this.TargetName;
        }

        private void toolStripButtonFont_Click(object sender, EventArgs e)
        {
            FontDialog fontDlg = new FontDialog();
            fontDlg.ShowColor = true;
            fontDlg.Font = this.richTextBoxEdit.Font;
            fontDlg.Color = this.richTextBoxEdit.ForeColor;
            fontDlg.ShowDialog();
            this.richTextBoxEdit.Font = fontDlg.Font;
            this.richTextBoxEdit.ForeColor = fontDlg.Color;
        }

        private void toolStripButtonFileSend_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDlg = new OpenFileDialog();
            openDlg.Multiselect = true;
            openDlg.RestoreDirectory = true;
            openDlg.Filter = "All Files|*.*";
            if (openDlg.ShowDialog() == DialogResult.OK)
            {
                SendFiles(openDlg.FileNames);
            }
        }

        private void richTextBoxEdit_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter && !e.Shift && !e.Alt)
            {
                if (!(e.Control ^ CtrlEnter2Send))
                {
	                e.SuppressKeyPress = true;
	                btnSend_Click(this.btnSend, e);
                } 
            }
            else if (e.KeyCode == Keys.V && e.Control && !e.Shift && !e.Alt)
            {
                if (Clipboard.ContainsFileDropList())
                {
//                     System.Collections.Specialized.StringCollection strcol = Clipboard.GetFileDropList();
                    string[] strcol = (string[])Clipboard.GetData(DataFormats.FileDrop);
                    SendFiles(strcol);
                    string strs = "";
                    foreach (string str in strcol)
                    {
                        strs += str + "\n";
                    }
                    System.Diagnostics.Debug.Print(strs);
                    e.Handled = true;
                }
                else
                {
                    this.richTextBoxEdit.Paste();
                    e.Handled = true;
                }
            }
        }

        private void richTextBoxEdit_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                //TODO 文件传送
                System.Diagnostics.Debug.Print("File Transfer");
                SendFiles((string[])e.Data.GetData(DataFormats.FileDrop));
                e.Effect = DragDropEffects.None;
            }
        }

        private void richTextBoxShow_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.richTextBoxShow.SelectionLength > 0)
                {
                    DataObject obj = new DataObject(this.richTextBoxShow.SelectedText);
                    obj.SetData("Rich Text Format", this.richTextBoxShow.SelectedRtf);
                    this.richTextBoxShow.DoDragDrop(obj, DragDropEffects.Copy | DragDropEffects.Move);
                }
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (this.richTextBoxEdit.Text == "" || !this.btnSend.Enabled)
                return;
            this.richTextBoxEdit.SelectionStart = 0;
            this.richTextBoxEdit.SelectionLength = this.richTextBoxEdit.TextLength;
            this.richTextBoxEdit.SelectionIndent = 15;
            p2p.Message msg = new p2p.Message(LocalName, TargetName, DateTime.Now, this.richTextBoxEdit.Rtf);
            this.msgPro.SendMessage(msg);
            AddMessage(msg.Time, msg.SenderName, msg.Content);
            this.richTextBoxEdit.Text = "";
            this.richTextBoxEdit.SelectionIndent = 0;
        }

        private void btnEnter_Click(object sender, EventArgs e)
        {
            this.contextMenuStripEnterWay.Show((Control)sender, new Point(0, 0), ToolStripDropDownDirection.BelowLeft);
        }

        private void flowLayoutPanelFileTransfer_SizeChanged(object sender, EventArgs e)
        {
            foreach (Control ctrl in this.flowLayoutPanelFileTransfer.Controls)
            {
                ctrl.Width = this.flowLayoutPanelFileTransfer.Width;
            }
        }

        private void PrivateChatCtrl_Enter(object sender, EventArgs e)
        {
            Client.UserStatus status = this.Tag as Client.UserStatus;
            this.btnSend.Enabled = status.online;
        }

        private void Way2SendToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ToolStripMenuItem item in this.contextMenuStripEnterWay.Items)
            {
                if (item == sender)
                {
                    item.Checked = true;
                    if (item.Text.Contains("Ctrl"))
                        CtrlEnter2Send = true;
                    else CtrlEnter2Send = false;
                }
                else
                {
                    item.Checked = false;
                }
            }
        }

        #region ContextMenuStrip Methods

        private void contextMenuStripEdit_Opening(object sender, CancelEventArgs e)
        {
            if (this.richTextBoxEdit.SelectionLength > 0)
            {
                this.CutToolStripMenuItem.Enabled = true;
                this.CopyToolStripMenuItem.Enabled = true;
            }
            else
            {
                this.CutToolStripMenuItem.Enabled = false;
                this.CopyToolStripMenuItem.Enabled = false;
            }
            if (Clipboard.GetDataObject().GetFormats().Length > 0)
            {
                this.PasteToolStripMenuItem.Enabled = true;
            }
            else
            {
                this.PasteToolStripMenuItem.Enabled = false;
            }
        }

        private void CutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SendKeys.SendWait("^x");
        }

        private void CopyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SendKeys.SendWait("^c");
        }

        private void PasteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsFileDropList())
            {
//                 System.Collections.Specialized.StringCollection strcol = Clipboard.GetFileDropList();
                string[] strcol = (string[])Clipboard.GetData(DataFormats.FileDrop);
                SendFiles(strcol);
                string strs = "";
                foreach (string str in strcol)
                {
                    strs += str + "\n";
                }
                System.Diagnostics.Debug.Print(strs);
            }
            else
            {
                this.richTextBoxEdit.Paste();
            }
        }

        #endregion

        #region File Transfer Methods

        private void SendFiles(string[] files)
        {
            foreach (string file in files)
            {
                FileInfo fi = new FileInfo(file);
                FileAttr fileAttr = new FileAttr(file, fi.Length);
                this.msgPro.SendFileTransferApply(this.TargetName, fileAttr);
                //UI操作
                AddFileTransfer(fileAttr, false);
            }
        }

        private void ctrl_FileTransferFinished(object sender, FileTransferFinishedEventArgs e)
        {
            FileTransferCtrl ctrl = sender as FileTransferCtrl;
            if (e.Succeeded)
            {
	            if (ctrl.receive)
	                AddAnnounce(DateTime.Now, "您已经成功接收" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件！\n");
	            else
	                AddAnnounce(DateTime.Now, "您已经成功发送" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件！\n");
            }else if (e.Crashed)
            {
                if (ctrl.receive)
                    AddAnnounce(DateTime.Now, "由于网络错误，" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件接收失败！\n");
                else
                    AddAnnounce(DateTime.Now, "由于网络错误，" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件发送失败！\n");
            }
            if (ctrl.btnConfirm.Text != "打开")
                FileTransferCtrlRemove(ctrl);
        }

        private void btnConfirm_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            FileTransferCtrl ctrl = btn.Tag as FileTransferCtrl;
            if (btn.Text == "打开")
            {
                System.Diagnostics.Process.Start(ctrl.fileAttr.FileName);
                FileTransferCtrlRemove(ctrl);
                return;
            }
            SaveFileDialog saveDlg = new SaveFileDialog();
            saveDlg.RestoreDirectory = true;
            string ext = Path.GetExtension(ctrl.fileAttr.FileName).Remove(0, 1);
            saveDlg.Filter = ext + " Files|*." + ext;
            saveDlg.DefaultExt = ext;
            saveDlg.FileName = ctrl.fileAttr.FileName;
            if (saveDlg.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            ctrl.fileAttr.FileName = saveDlg.FileName;
            this.msgPro.SendFileTransferAck(this.TargetName, ctrl.fileAttr.No, ctrl.DoReceive());
        }

        private void btnDenyCancel_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            FileTransferCtrl ctrl = btn.Tag as FileTransferCtrl;
            if (btn.Text == "拒绝")
            {
                this.msgPro.SendFileTransferDeny(this.TargetName, ctrl.fileAttr.No);
                AddAnnounce(DateTime.Now, "您拒绝了" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件的传送！\n");
            }
            else if (btn.Text == "取消")
            {
                this.msgPro.SendFileTransferCancel(this.TargetName, ctrl.fileAttr.No, ctrl.fileAttr.SourceName);
                AddAnnounce(DateTime.Now, "您取消了" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件的传送！\n");
            }
            else if (btn.Text == "关闭")
            {
            }
            FileTransferCtrlRemove(ctrl);
        }

        private void FileTransferCtrlRemove(FileTransferCtrl ctrl)
        {
            ctrl.DoCancel();
            this.flowLayoutPanelFileTransfer.Controls.Remove(ctrl);
            if (this.flowLayoutPanelFileTransfer.Controls.Count == 0)
            {
                this.tabControl1.Controls.Remove(this.tabPageFileTransfer);
                this.FileTransfering = false;
            }
            ctrl.Dispose();
        }

        private void msgPro_FileCanceled(object sender, FileCanceledEventArgs e)
        {
            if (e.TargetName == this.TargetName)
            {
                string key = e.FileAttrSource + "." + e.FileAttrNo.ToString();
                if (this.flowLayoutPanelFileTransfer.Controls.ContainsKey(key))
                {
                    FileTransferCtrl ctrl = (FileTransferCtrl)this.flowLayoutPanelFileTransfer.Controls[key];
                    AddAnnounce(DateTime.Now, "对方已经取消了" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件的传送！\n");
                    FileTransferCtrlRemove(ctrl);
                }
            }
        }

        private void msgPro_FileDenied(object sender, FileTransferEventArgs e)
        {
            if (e.TargetName == this.TargetName)
            {
                string key = this.LocalName + "." + e.FileAttrNo.ToString();
                if (this.flowLayoutPanelFileTransfer.Controls.ContainsKey(key))
                {
                    FileTransferCtrl ctrl = (FileTransferCtrl)this.flowLayoutPanelFileTransfer.Controls[key];
                    AddAnnounce(DateTime.Now, "对方拒绝了" + Path.GetFileName(ctrl.fileAttr.FileName) + "文件的传送！\n");
                    FileTransferCtrlRemove(ctrl);
                }
            }
        }

        private void msgPro_FileConfirmed(object sender, FileConfirmedEventArgs e)
        {
            if (e.TargetName == this.TargetName)
            {
                string key = this.LocalName + "." + e.FileAttrNo.ToString();
                if (this.flowLayoutPanelFileTransfer.Controls.ContainsKey(key))
                {
                    FileTransferCtrl ctrl = (FileTransferCtrl)this.flowLayoutPanelFileTransfer.Controls[key];
                    ctrl.DoSend(e.EndPoint);
                }
            }
        }

        #endregion

        #endregion

        #region Public Methods

        public void AddMessage(DateTime time, string name, string rtf)
        {
//             this.richTextBoxShow.AppendText("");
            this.richTextBoxShow.SelectionStart = this.richTextBoxShow.TextLength;
            this.richTextBoxShow.SelectionLength = 0;
            this.richTextBoxShow.SelectionFont = DefaultFont;
            this.richTextBoxShow.SelectionColor = DefaultForeColor;
            this.richTextBoxShow.SelectedText = name + ' ' + time.ToString() + '\n';
            this.richTextBoxShow.SelectedRtf = rtf;
            this.richTextBoxShow.SelectionIndent = 0;
            this.richTextBoxShow.ScrollToCaret();
        }

        public void AddAnnounce(DateTime time, string text)
        {
//             this.richTextBoxShow.AppendText("");
            this.richTextBoxShow.SelectionStart = this.richTextBoxShow.TextLength;
            this.richTextBoxShow.SelectionLength = 0;
            this.richTextBoxShow.SelectionFont = DefaultFont;
            this.richTextBoxShow.SelectionColor = DefaultForeColor;
            this.richTextBoxShow.SelectedText = time.ToString() + '\n';
            this.richTextBoxShow.SelectionIndent = 15;
            this.richTextBoxShow.SelectedText = text;
            this.richTextBoxShow.SelectionIndent = 0;
            this.richTextBoxShow.ScrollToCaret();
        }

        public void AddFileTransfer(FileAttr fileAttr, bool fromApply)
        {
            if (this.flowLayoutPanelFileTransfer.Controls.Count == 0)
            {
                this.tabControl1.Controls.Add(this.tabPageFileTransfer);
                this.FileTransfering = true;
            }
            FileTransferCtrl ctrl = new FileTransferCtrl(fileAttr, fromApply);
            ctrl.Width = this.flowLayoutPanelFileTransfer.Width;
            ctrl.Margin = new Padding(0, ctrl.Margin.Top, 0, ctrl.Margin.Bottom);
            ctrl.btnDenyCancel.Click += new EventHandler(btnDenyCancel_Click);
            if (fromApply)
            {
                fileAttr.SourceName = this.TargetName;
                ctrl.btnConfirm.Visible = true;
                ctrl.btnConfirm.Click += new EventHandler(btnConfirm_Click);
                ctrl.btnDenyCancel.Text = "拒绝";
            }
            else
            {
                fileAttr.SourceName = this.LocalName;
                ctrl.btnConfirm.Visible = false;
                ctrl.btnDenyCancel.Text = "取消";
            }
            ctrl.Name = fileAttr.SourceName + "." + fileAttr.No.ToString();
            ctrl.FileTransferFinished += new p2p.FileTransferFinishedEventHandler(ctrl_FileTransferFinished);
            this.flowLayoutPanelFileTransfer.Controls.Add(ctrl);
            this.tabControl1.SelectedTab = this.tabPageFileTransfer;
        }

        public void CancelAllFileTransfer()
        {
            foreach (Control ctrl in this.flowLayoutPanelFileTransfer.Controls)
            {
                FileTransferCtrl ftCtrl = ctrl as FileTransferCtrl;
                FileTransferCtrlRemove(ftCtrl);
            }
        }

        public void EditBoxFocus()
        {
            this.richTextBoxEdit.Focus();
        }

        #endregion

    }
}
